#include "../Server.hpp"
#include <fstream>
#include <regex>
#define DEFAULT_TIMEOUT 10

std::unordered_map<int, std::string> _status =
        {
            {100, "Continue"},
            {101, "Switching Protocol"},
            {102, "Processing"},
            {103, "Early Hints"},
            {200, "OK"},
            {201, "Created"},
            {202, "Accepted"},
            {203, "Non-Authoritative Information"},
            {204, "No Content"},
            {205, "Reset Content"},
            {206, "Partial Content"},
            {207, "Multi-Status"},
            {208, "Already Reported"},
            {226, "IM Used"},
            {300, "Multiple Choice"},
            {301, "Moved Permanently"},
            {302, "Found"},
            {303, "See Other"},
            {304, "Not Modified"},
            {305, "Use Proxy"},
            {306, "unused"},
            {307, "Temporary Redirect"},
            {308, "Permanent Redirect"},
            {400, "Bad Request"},
            {401, "Unauthorized"},
            {402, "Payment Required"},
            {403, "Forbidden"},
            {404, "Not Found"},
            {405, "Method Not Allowed"},
            {406, "Not Acceptable"},
            {407, "Proxy Authentication Required"},
            {408, "Request Timeout"},
            {409, "Conflict"},
            {410, "Gone"},
            {411, "Length Required"},
            {412, "Precondition Failed"},
            {413, "Payload Too Large"},
            {414, "URI Too Long"},
            {415, "Unsupported Media Type"},
            {416, "Range Not Satisfiable"},
            {417, "Expectation Failed"},
            {418, "I'm a teapot"},
            {421, "Misdirected Request"},
            {422, "Unprocessable Entity"},
            {423, "Locked"},
            {424, "Failed Dependency"},
            {425, "Too Early"},
            {426, "Upgrade Required"},
            {428, "Precondition Required"},
            {429, "Too Many Requests"},
            {431, "Request Header Fields Too Large"},
            {451, "Unavailable For Legal Reasons"},
            {501, "Not Implemented"},
            {502, "Bad Gateway"},
            {503, "Service Unavailable"},
            {504, "Gateway Timeout"},
            {505, "HTTP Version Not Supported"},
            {506, "Variant Also Negotiates"},
            {507, "Insufficient Storage"},
            {508, "Loop Detected"},
            {510, "Not Extended"},
            {511, "Network Authentication Required"} };

 std::unordered_map<std::string, std::string> _ext =
        {
            {".aac", "audio/aac"},
            {".abw", "application/x-abiword"},
            {".arc", "application/x-freearc"},
            {".avi", "video/x-msvideo"},
            {".azw", "application/vnd.amazon.ebook"},
            {".bin", "application/octet-stream"},
            {".bmp", "image/bmp"},
            {".bz", "application/x-bzip"},
            {".bz2", "application/x-bzip2"},
            {".csh", "application/x-csh"},
            {".css", "text/css"},
            {".csv", "text/csv"},
            {".doc", "application/msword"},
            {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
            {".eot", "application/vnd.ms-fontobject"},
            {".epub", "application/epub+zip"},
            {".gif", "image/gif"},
            {".htm", "text/html"},
            {".html", "text/html"},
            {".ico", "image/vnd.microsoft.icon"},
            {".ics", "text/calendar"},
            {".jar", "application/java-archive"},
            {".jpeg", "image/jpeg"},
            {".jpg", "image/jpeg"},
            {".js", "text/javascript"},
            {".json", "application/json"},
            {".jsonld", "application/ld+json"},
            {".mid", "audio/midi"},
            {".midi", "audio/x-midi"},
            {".mjs", "text/javascript"},
            {".mp3", "audio/mpeg"},
            {".mpeg", "video/mpeg"},
            {".mpkg", "application/vnd.apple.installer+xml"},
            {".odp", "application/vnd.oasis.opendocument.presentation"},
            {".ods", "application/vnd.oasis.opendocument.spreadsheet"},
            {".odt", "application/vnd.oasis.opendocument.text"},
            {".oga", "audio/ogg"},
            {".ogv", "video/ogg"},
            {".ogx", "application/ogg"},
            {".otf", "font/otf"},
            {".png", "image/png"},
            {".pdf", "application/pdf"},
            {".ppt", "application/vnd.ms-powerpoint"},
            {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
            {".rar", "application/x-rar-compressed"},
            {".rtf", "application/rtf"},
            {".sh", "application/x-sh"},
            {".svg", "image/svg+xml"},
            {".swf", "application/x-shockwave-flash"},
            {".tar", "application/x-tar"},
            {".tif", "image/tiff"},
            {".tiff", "image/tiff"},
            {".ttf", "font/ttf"},
            {".txt", "text/plain"},
            {".vsd", "application/vnd.visio"},
            {".wav", "audio/wav"},
            {".weba", "audio/webm"},
            {".webm", "video/webm"},
            {".webp", "image/webp"},
            {".woff", "font/woff"},
            {".woff2", "font/woff2"},
            {".xhtml", "application/xhtml+xml"},
            {".xls", "application/vnd.ms-excel"},
            {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
            {".xml", "application/xml"},
            {".xul", "application/vnd.mozilla.xul+xml"},
            {".zip", "application/zip"},
            {".3gp", "video/3gpp"},
            {".3g2", "video/3gpp2"},
            {".7z", "application/x-7z-compressed"} };            
// 功能类：提供一些琐碎的功能接口
class Util
{
    // 统一设置为静态函数，没有this指针
public:
    // 字符串分割函数 - 返回结果个数
    static size_t StrSplit(const std::string& src, const std::string sep, std::vector<std::string>* array)
    {
        int offset = 0;
        while (offset < src.size())
        {
            auto pos = src.find(sep, offset);
            if (pos == std::string::npos)
            {
                // 说明找到文件末尾还没找到
                // abc,bcd - 我们还要把最后一段处理了
                array->push_back(src.substr(offset));
                return array->size();
            }
            if (pos != offset)
            {
                array->push_back(src.substr(offset, pos - offset));
            }
            offset = pos + sep.size();
        }
        return array->size();
    }
    // 读取文件内容
    static bool ReadFile(const std::string& filename, std::string* buffer)
    {
        std::ifstream in(filename.c_str(), std::ios::binary);
        if (!in.is_open())
        {
            ERR_LOG("filename: %s not found!!", filename.c_str());
            return false;
        }
        int fullsize = 0;
        in.seekg(0, in.end);
        fullsize = in.tellg(); // 获取文件的总大小。
        in.seekg(0, in.beg);   // 回到初始的位置
        buffer->resize(fullsize);
        in.read(&((*buffer)[0]), fullsize);
        if (in.good() == false)
        {
            ERR_LOG("filename: %s read error!!!", filename.c_str());
            return false;
        }
        return true;
    }
    // 写入文件内容 - 未来用户可能会上传文件，我们需要对内容进行保存
    static bool WriteFile(const std::string& filename, const std::string& buffer)
    {
        // std::ios::trunc: 保证每一次文件的内容都是重新写的
        std::ofstream out(filename.c_str(), std::ios::binary | std::ios::trunc);
        if (!out.is_open())
        {
            ERR_LOG("filename: %s not found!!", filename.c_str());
            return false;
        }
        out.write(buffer.c_str(), buffer.size());
        if (out.good() == false)
        {
            ERR_LOG("filename: %s write error!!!", filename.c_str());
            return false;
        }
        return true;
    }
    // Uel编码，url中一些特殊的字符我们需要对其进行编码和解码 - w3c标准规定查询字符串中空格需要替换为 + 号
    /*RFC3986文档规定，.-_~ 字母和数字是绝不能编码的，其他的特殊符号需要编码为 %HH，例如C++ -> C%2B%2B
    而查询字符串中 ?usr=c  &passwd=123 中 c  需要编译为 c++
    */
    static std::string UrlEncode(const std::string& url, bool space_convert_2_plus = false)
    {
        std::string res;
        for (int i = 0; i < url.size(); i++)
        {
            if (url[i] == '.' || url[i] == '-' || url[i] == '_' || url[i] == '~' || isalnum(url[i]))
            {
                res += url[i];
                continue;
            }
            if (url[i] == ' ' && space_convert_2_plus)
            {
                res += '+';
                continue;
            }
            char tmp[4] = { 0 };
            snprintf(tmp, 4, "%02X", url[i]);
            res += tmp;
        }
        return res;
    }
    static int Char2Int(char c)
    {
        if (c >= '0' && c <= '9')
            return c - '0';
        else if (c >= 'a' && c <= 'z')
            return c - 'a' + 10;
        else if (c >= 'A' && c <= 'Z')
            return c - 'A' + 10;
        else
            return -1;
    }
    static std::string UrlDecode(const std::string& url, bool plus_convert_2_space = false)
    {
        std::string res;
        for (int i = 0; i < url.size(); i++)
        {
            if (url[i] == '%' && (i + 2) < url.size())
            {
                int v1 = Char2Int(url[i + 1]);
                int v2 = Char2Int(url[i + 2]);
                char c = v1 * 16 + v2;
                res += c;
                //%2B, i+=2，然后再次循环i+1，总共是i+3，刚好是下一个字符
                i += 2;
                continue;
            }

            if (url[i] == '+' && plus_convert_2_space)
            {
                res += ' ';
                continue;
            }
            res += url[i];
        }
        return res;
    }
    // 状态码 -> 状态码描述
    static std::string Statu2Desc(int status)
    {
        
        auto it = _status.find(status);
        if (it == _status.end())
        {
            return "UnKnown";
        }
        return it->second;
    }
    // 文件后缀 -> http的文件类型
    static std::string ExtMime(const std::string& ext)
    {
       
        auto it = _ext.find(ext);
        if (it == _ext.end())
        {
            return "application/octet-stream";
        }
        return it->second;
    }
    // 是否是一个目录
    static bool IsDirectory(const std::string& filename) {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0) {
            ERR_LOG("STAT FAIL!!");
            return false;
        }
        return S_ISDIR(st.st_mode);
    }
    // 是否是一个普通文件 | 可以判断文件不存在
    static bool IsRegular(const std::string& filename) {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0) {
            // ERR_LOG("STAT FAIL!!");
            return false;
        }
        return S_ISREG(st.st_mode);
    }
    // 验证http资源路径是否有效
    //什么是有效路径呢？ 
    /*
    例如我们请求的资源路径是 /index.html 这个是合法的
    /http/../../index.html 此时我们用户请求的资源是当前网页的相对根目录的上级目录，这是不允许的，用户只能请求网页根目录的内容
    /http/source/../../../http 这样虽然最终结果是可以的，但是由于过程请求了网站根目录的上级目录，我们也算无效
    */
    static bool ValidPath(const std::string url) {
        std::vector<std::string> array;
        StrSplit(url, "/", &array);
        int level = 0;
        for (auto& x : array) {
            if (x == "..") {
                if (--level < 0) return false;
                continue;
            }
            ++level;
        }
        return true;
    }
};

class HttpRequest
{
public:
    std::string _method; //请求方法
    std::string _path;   //请求资源路径
    std::string _version;//请求版本信息
    std::string _body;   //请求正文
    std::smatch _st;
    std::unordered_map<std::string, std::string> _headers; //请求报头
    std::unordered_map<std::string, std::string> _params; //请求字符串   
    //重置信,防止上一次残留的数据影响结果
    void ReSet()   
    {
        _method.clear();
        _path.clear();
        _version.clear();
        _body.clear();
        _headers.clear();
        _params.clear();
        //std::smatch并没有clear接口，所以我们创建一个空的然后进行交换即可。
        std::smatch tmp;
        _st.swap(tmp);
    }
    void SetHeader(const std::string& key, const std::string& val) { _headers[key] = val; }
    bool HasHeader(const std::string& key) const { return _headers.find(key) != _headers.end(); }
    std::string GetHeader(const std::string& key)  const  {
        if (HasHeader(key)) return _headers.at(key);
        //没有返回空
        return "";
    }
    void SetParma(const std::string& key, const std::string& val) { _params[key] = val; }
    bool HasParma(const std::string& key) { return _params.find(key) != _params.end(); }
    std::string GetParma(const std::string& key) {
        if (HasParma(key)) return _params[key];
        //没有返回空        
        return "";
    }
    //短连接返回true,长连接返回false    
    bool Close()  const {
        //如果没有Connection这个字段或者有这个字段并且是close那么就是短连接
        return (!HasHeader("Connection")) || (GetHeader("Connection") == "close");
    }
    ssize_t ContentLength() const {
        if (HasHeader("Content-Length")) {
            return std::stoi(GetHeader("Content-Length"));
        }
        return 0;
    }
};

class HttpResponse
{
public:
    int _status; //状态码
    std::string _body; //请求正文
    std::string _redirect_url; //重定向路径
    bool _is_redirect; //是否进行重定向
    std::unordered_map<std::string, std::string> _headers; //请求报头
    HttpResponse() :_status(200), _is_redirect(false) {}
    HttpResponse(int status) :_status(status), _is_redirect(false) {}
    void ReSet() {
        _status = 200;
        _is_redirect = false;
        _body.clear();
        _redirect_url.clear();
        _headers.clear();
    }
    void SetHeader(const std::string& key, const std::string& val) { _headers[key] = val; }
    bool HasHeader(const std::string& key) { return _headers.find(key) != _headers.end(); }
    std::string GetHeader(const std::string& key) {
        if (HasHeader(key)) return _headers[key];
        //没有返回空
        return "";
    }
    //设置请求正文，顺便设置文件类型
    void SetContent(const std::string body, const std::string& type) {
        _body = body;
        SetHeader("Content-type", type);
    }
    //这里并不直接设置响应报头，后面如果有设置判断一下标志然后再进行设置
    void SetRedirectUrl(const std::string& url, int status = 302) {
        _status = status;
        _is_redirect = true;
        _redirect_url = url;
    }
};

typedef enum {
    HTTP_RECV_LINE,
    HTTP_RECV_HEAD,
    HTTP_RECV_BODY,
    HTTP_RECV_OVER,
    HTTP_RECV_ERROR
}HttpStatus;
//定义最大的一行长度 8kb
#define MAX_LINE 8092 
class HttpContext
{
private:
    int _resp_status; //响应状态码
    HttpStatus _recv_status; //解析请求状态码
    HttpRequest _over_info; //解析之后的完整报文
private:
    bool ParseHttpLine(const std::string& line) {
        //1. 直接使用正则进行匹配
        //2. 如果匹配失败的直接返回false
        //3. 设置进入对应的_over_info
        std::smatch st;
        //如果想要忽略大小写，可以在构造std::regex的后面添加std::regex::icase
        std::regex e("(GET|HEAD|PUT|POST|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\r|\r\n|\n)?",std::regex::icase);
        // std::regex e ("(GET|HEAD|PUT|POST|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\r|\r\n|\n)?"); //匹配规则，直接使用 () 包起来
        bool ret = std::regex_match(line, st, e);
        if (!ret) {
            _resp_status = 400; //BAD REQUEST
            _recv_status = HTTP_RECV_ERROR;
            return false;
        }
        /*
        0 : GET /testdir/login HTTP/1.1
        1 : GET
        2 : /testdir/login
        3 :
        4 : HTTP/1.1
        */
        _over_info._method = st[1];
        //最后两个参数: 结果保存的位置，需要进行的操作。 *first = op(*result); first++; result++。
        std::transform(_over_info._method.begin(),_over_info._method.end(),_over_info._method.begin(),::toupper);
        // for (auto& c : _over_info._method){
        //     if (islower(c)){
        //         toupper(c);
        //     }
        // }
        //资源路径不需要空格 -> + 号
        _over_info._path = Util::UrlDecode(st[2], false);
        _over_info._version = st[4];
        std::vector<std::string> parmas;
        //usrname=xiaoming&passwd=123
        Util::StrSplit(st[3], "&", &parmas);
        for (auto& s : parmas) {
            auto pos = s.find("=");
            if (pos == std::string::npos) {
                //那就说明此时的格式是不正确的
                _resp_status = 400; //BAD REQUEST
                _recv_status = HTTP_RECV_ERROR;
                return false;
            }
            //查询参数中需要设置空格 -> 加号
            std::string key = Util::UrlDecode(s.substr(0,pos), true);
            std::string val = Util::UrlDecode(s.substr(pos + 1), true);
            _over_info.SetParma(key, val);
        }
        return true;
    }
    //解析请求信息的步骤
    bool RecvHttpLine(Buffer* buff) {
        if (_recv_status != HTTP_RECV_LINE) return false;
        //这里我们获取之后直接取出来就可以了
        std::string line = buff->GetLineAndPop();
        //我们需要关注两个问题:1. 数据不足一行，2.数据长太大了，大的不合理
        if (line.empty()) {
            if (buff->ReadAbleSize() > MAX_LINE) {
                //设置响应状态码和解析状态
                _resp_status = 414; //URL TOO LONG
                _recv_status = HTTP_RECV_ERROR;
                return false;
            }
            //说明此时还是不足一行的，继续读取，这里没有找到的话直接返回也是没有事的。
            return true;
        }
        //说明此时读到了数据，还是要判断一下数据长度
        if (line.size() > MAX_LINE) {
            _resp_status = 414; //URL TOO LONG
            _recv_status = HTTP_RECV_ERROR;
            return false;
        }
        bool ret = ParseHttpLine(line);
        if (!ret) {
            //上面如果出错了已经设置过状态码了
            return false;
        }
        //处理完毕之后要修改状态
        _recv_status = HTTP_RECV_HEAD;
        return ret;
    }
    bool ParseHttpHead(std::string& line) {
        //1. 按照 ": " 进行分割，key: val\r\n.......
        //这里需要注意我们分割的都是例如： keep-alive\r\n，所以为了后面正确的判断我们需要把\r\n去掉
        if (line.back() == '\n') line.pop_back();
        if (line.back() == '\r') line.pop_back();
        auto pos = line.find(": ");
        if (pos == std::string::npos) {
            //那就说明此时的格式是不正确的
            _resp_status = 400; //BAD REQUEST
            _recv_status = HTTP_RECV_ERROR;
            return false;
        }
        //这里注意是从0开始，然后pos个字符
        std::string key = line.substr(0,pos);
        std::string val = line.substr(pos + 2);
        _over_info.SetHeader(key, val);
        return true;
    }
    bool RecvHttpHead(Buffer* buff) {
        if (_recv_status != HTTP_RECV_HEAD) return false;
        while (1) {
            //这里我们获取之后直接取出来就可以了
            std::string line = buff->GetLineAndPop();
            //我们需要关注两个问题:1. 数据不足一行，2.数据长太大了，大的不合理
            if (line.empty()) {
                if (buff->ReadAbleSize() > MAX_LINE) {
                    //设置响应状态码和解析状态
                    _resp_status = 414; //URL TOO LONG
                    _recv_status = HTTP_RECV_ERROR;
                    return false;
                }
                //说明此时还是不足一行的，继续读取，这里没有找到的话直接返回也是没有事的。
                return true;
            }
            //说明此时读到了数据，还是要判断一下数据长度
            if (line.size() > MAX_LINE) {
                _resp_status = 414; //URL TOO LONG
                _recv_status = HTTP_RECV_ERROR;
                return false;
            }
            //说明此时读取到空行了
            if (line == "\n" || line == "\r\n")
                break;
            bool ret = ParseHttpHead(line);
            if (!ret) return false;
        }
        _recv_status = HTTP_RECV_BODY;
        return true;
    }
    bool RecvHttpBody(Buffer* buff) {
        if (_recv_status != HTTP_RECV_BODY) return false;
        //1. 获取报文的总长度
        uint32_t content_length = _over_info.ContentLength();
        if (content_length == 0) {
            //说明没有正文，直接返回即可
            _recv_status = HTTP_RECV_OVER;
            return true;
        }
        uint32_t real_len = content_length - _over_info._body.size();
        //2. 与当前body的长度对比，看一看是否是一个完整的报文
        if (real_len > buff->ReadAbleSize()) {
            //说明此时缓冲区的数据并不是完整的数据，我们还需要接着读取数据
            _over_info._body.append(buff->ReadPositoin(), buff->ReadAbleSize());
            buff->ReadMoveOffset(buff->ReadAbleSize());
            return true;
        }
        //此时说明缓冲区中已经有了完整的数据，我们直接把剩余的数据读取上来，然后设置状态，对数据进行处理
        _over_info._body.append(buff->ReadPositoin(), real_len);
        buff->ReadMoveOffset(real_len);
        _recv_status = HTTP_RECV_OVER;
        return true;
    }
public:
    HttpContext() :_recv_status(HTTP_RECV_LINE), _resp_status(200) {}
    //获取响应状态码
    int RespStatus() { return _resp_status; }
    void Reset() {
        _recv_status = HTTP_RECV_LINE;
        _resp_status = 200;
        _over_info.ReSet();
    }
    //获取解析请求状态码
    HttpStatus ResqStatus() { return _recv_status; }
    //获取解析后的完整请求信息
    HttpRequest& AfterParseInfo() { return _over_info; }
    //解析请求信息
    void ParseHttpResq(Buffer* buff) {
        switch (_recv_status) {
            //注意这里不需要break，因为我们要么出错返回设置状态码， 不匹配然后自动退出
            //要么处理玩一个完整的报文之后也设置over状态码，不匹配自动退出
        case HTTP_RECV_LINE:    RecvHttpLine(buff);
        case HTTP_RECV_HEAD:    RecvHttpHead(buff);
        case HTTP_RECV_BODY:    RecvHttpBody(buff);
        }
        return;
    }
};

using CallBack = std::function<void(const HttpRequest& req, HttpResponse& rsp)>;
class HttpServer
{
private:
    //请求方法 + 资源路径对应的回调处理函数
    using Handlers = std::vector<std::pair<std::regex, CallBack>>;
    Handlers _get_route;
    Handlers _post_route;
    Handlers _put_route;
    Handlers _head_route;
    Handlers _delete_route;
    //高并发服务器
    TcpServer _server;
    std::string _basedir; //网页的相对根目录
private:
    bool IsFileHandler(const HttpRequest& req){
        //1. 是否设置的相对根目录
        if (_basedir.empty()){
            return false;
        }
        //2. 必须是GET或者HEAD，这里要注意，有可能http请求中的方法是 get。我们要把method转为大写，再来判断
        if (req._method != "GET" && req._method != "HEAD"){

            return false;
        }
        //3. 是否是合法的路径
        //这里需要注意，我们得到的只是 / 后者 /image/这样的路径，需要凭借basedir来进行判断
        std::string req_path = _basedir + req._path;
        if (req_path.back() == '/'){
            req_path += "index.html";
        }
        if (!Util::ValidPath(req_path)){
            return false;
        }
        // DBG_LOG("request url: %s",req_path.c_str());
        //4. 文件是否存在，是否是一个普通文件，是否存在。
        if (!Util::IsRegular(req_path)){
            return false;
        }
        
        return true;
    }
    //获取静态资源的处理函数
    void FileHandler(const HttpRequest& req, HttpResponse* rsp){
        std::string req_path = _basedir + req._path;
        if (req_path.back() == '/'){
            req_path += "index.html";
        }
        std::string body;
        bool ret = Util::ReadFile(req_path,&body);
        if (!ret){
            //这里也不应该会失败，因为已经提前判断过了文件是否存在
            return; 
        }
        //此时文件读取成功
        rsp->SetContent(body,Util::ExtMime(".html"));
        return;
    }
    //进行功能性请求处理的函数
    void Dispacher(HttpRequest& req, HttpResponse* rsp,Handlers& handlers){
        //这里需要注意我们的路由表中存储的并不是字符串，而是正则匹配的规则
        /*
        例如 /numbers/(\d.*) 那么我们可以匹配成功的字符串就是 /numbers/123 ... ，只有是这样类型的字符串才执行/numbers/(\d.*)对应的
        回调函数。这里我们直接遍历当前方法存储的所有匹配规则，如果找到了就执行回调函数，如果没有找到就把状态码设置为404
        */
       for (auto& handler : handlers){
            //但是在我们初始化std::regex re，每一次都要进行编译，他会把字符串生成为一种方便进行匹配的格式，这样效率太低了，所以在我们的路由表当中，直接存储
            //std::regex，这样就不需要每一次遍历的时候都要再编译一次了。这里需要注意，因为哈希表中key不能修改，所以这里我们需要使用const
            const std::regex &re = handler.first;
            const auto& functor = handler.second;
            //原始字符串，保存结果的数组，匹配规则
            bool ret = std::regex_match(req._path,req._st,re);
            if (!ret){
                //如果没找到匹配的就继续找到
                continue;
            }
            std::cout << req._st[1] << std::endl;
            //此时找到了，执行对应的回调处理函数
            return functor(req,*rsp);
       }
       rsp->_status = 404;
       //构建错误的应答，不然不行
       ErrorHandler(rsp);
       return;
    }
    //通过请求来构建对应的相应回答
    void Route(HttpRequest& req, HttpResponse* rsp) {
        //GER 和 Head 都默认为静态资源的请求
        if (IsFileHandler(req)){
            return FileHandler(req,rsp);   
        }
        //功能性的请求
        if (req._method == "GET" || req._method == "HEAD"){
            return Dispacher(req,rsp,_get_route);
        }
        else if(req._method == "POST"){
            return Dispacher(req,rsp,_post_route);
        }
        else if(req._method == "PUT"){
            return Dispacher(req,rsp,_put_route);
        }
        else if(req._method == "DELETE"){
            return Dispacher(req,rsp,_delete_route);
        }
        //如果上面的方法都不是，那么就是我服务器不支持的
        rsp->_status = 405;//"Method Not Allowed"
        ErrorHandler(rsp);
        return;
    }
    //构建一个完整的http相应，并且发送
    void WriteResponse(const PtrConnect& con,const HttpRequest& req, HttpResponse* rsp) {
        std::stringstream ss;
        //构建请求行
        ss << req._version << " " << rsp->_status << " " << Util::Statu2Desc(rsp->_status) << "\r\n";
        //构建请求报头
        if (req.Close()) {
            //如果是短连接
            rsp->SetHeader("Connection","close");
        }
        else {
            rsp->SetHeader("Connection", "keep-alive");
        }
        //如果有正文的话，并且没有设置Content-Length,设置Content-Length
        if (!rsp->_body.empty() && !rsp->HasHeader("Content-Length")) {
            rsp->SetHeader("Content-Length", std::to_string(rsp->_body.size()));
        }
        //如果没有类型的话，并且没有设置Content-type,设置Content-type
        if (!rsp->_body.empty() && !rsp->HasHeader("Content-type")) {
            //我们也不知道应答的内容类型是什么类型的
            rsp->SetHeader("Content-type", "application/octet-stream");
        }
        //如果有重定向的话，设置重定向
        if (rsp->_is_redirect == true) {
            rsp->SetHeader("Location", rsp->_redirect_url);
        }
        //然后才是构建请求报头
        for (auto& x : rsp->_headers) {
            ss << x.first << ": " << x.second << "\r\n";
        }
        //空行
        ss << "\r\n";
        //如果有正文的话，构建正文
        if (!rsp->_body.empty()) {
            ss << rsp->_body;
        }
        // DBG_LOG("rspstr:%s",ss.str().c_str());
        con->Send(ss.str().c_str(), ss.str().size());
    }
    void ErrorHandler(HttpResponse* rsp) {
        //1. 组织一个错误展示页面
        std::string body;
        body += "<html>";
        body += "<head>";
        body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
        body += "</head>";
        body += "<body>";
        body += "<h1>";
        body += std::to_string(rsp->_status);
        body += " ";
        body += Util::Statu2Desc(rsp->_status);
        body += "</h1>";
        body += "</body>";
        body += "</html>";
        //2. 将页面数据，当作响应正文，放入rsp中
        rsp->SetContent(body, "text/html");
    }
    //一个连接建立成功之后的处理函数 - 设置上下文
    void Connected(const PtrConnect& con) {
        //说白了设置上下文，就是再这里面设置一个HttpReqeust对象，未来我们可以通过getcontext获取这个请求的指针。
        con->SetContext(HttpContext());
        DBG_LOG("get a new connection: %p", con.get());
    }
    //一个连接的业务处理函数，需要设置给高并发服务器，连接处理的步骤都在这里
    void Messaged(const PtrConnect& con, Buffer* buff) {
        // sleep(10);
        //只有当我们的读缓冲区中有数据到来的时候再接着处理
        while (buff->ReadAbleSize() > 0) {
            //1. 获取上下文
            HttpContext* context = con->Getontext()->get<HttpContext>();
            //2. 解析上下文，构建一个完整的HttpReqeust请求
            context->ParseHttpResq(buff);
            //如果此时的http解析请求失败了，那么直接返回错误信息即可。

            HttpResponse rsp(context->RespStatus()); //这里不要忘记，我们应答的状态码是上下文的状态码
            if (context->RespStatus() >= 400) {
                //执行错误的处理方法
                ErrorHandler(&rsp);
                WriteResponse(con, context->AfterParseInfo(), &rsp);
                context->Reset();
                buff->ReadMoveOffset(buff->ReadAbleSize());
                con->Shutdown();
                return;
            }
            if (context->ResqStatus() != HTTP_RECV_OVER) {
                //说明此时并没有完整的请求报文，等待下一次数据到来再执行。
                // DBG_LOG("还没有完整的数据到来!!");
                return;
            }
            HttpRequest& req = context->AfterParseInfo();
            //然后才是正常的流程处理
            //3. 通过路由表，进行任务处理
            Route(req, &rsp);
            //4. 构建一个http的响应应答字符串
            WriteResponse(con, req, &rsp);
            //5. 判断是短连接还是长连接，如果是短连接那么久直接关闭连接。
            if (req.Close()) {
                context->Reset(); 
                buff->ReadMoveOffset(buff->ReadAbleSize());
                //既然都要关闭连接了，我们直接重置上下文
                con->Shutdown();
                return;
            }
            //6. 每次获取上下文的时候，都要重置上下文，同时注意，我们不能先重置上下文，再去判断是否是长连接还是短连接，
            //因为req是从上下文中获取的，重置了之后就没有Connection字段了，就会判断为短连接
            context->Reset();            
        }
    }
public:
    HttpServer(uint16_t port,int timeout = DEFAULT_TIMEOUT) :_server(port)
        {
            _server.SetConnectedCallback(std::bind(&HttpServer::Connected,this,std::placeholders::_1));
            _server.SetMessageCallBack(std::bind(&HttpServer::Messaged,this,std::placeholders::_1,std::placeholders::_2));
            //这里我们把超时销毁功能放到构造函数这里，一个服务器应该默认要开启超时销毁功能，不然如果恶意连接连接上了就是不发消息的话，这就会一直占用系统资源。
            _server.EnableInactiveRelease(timeout);
        }
    //设置网站根目录
    void SetBaseDir(const std::string & basedir) {
        assert(Util::IsDirectory(basedir) == true);
        _basedir = basedir;
    }
    void SetThreadCount(int count) {_server.SetThreadCount(count);}
    void Listen(){
        _server.Start();
    }
    //五种请求方法的业务处理回调函数设置
    void Get(const std::string& str, const CallBack& callbackfunc){
        _get_route.push_back(std::make_pair(std::regex(str),callbackfunc));
    }
    void Post(const std::string& str, const CallBack& callbackfunc){
        _post_route.push_back(std::make_pair(std::regex(str),callbackfunc));
    }
    void Put(const std::string& str, const CallBack& callbackfunc){
        _put_route.push_back(std::make_pair(std::regex(str),callbackfunc));
    }
    void Delete(const std::string& str, const CallBack& callbackfunc){
        _delete_route.push_back(std::make_pair(std::regex(str),callbackfunc));
    }
};